package bsplib;

import bsplib.Vec3f;
import flash.Vector;

class BspNode
{
    public var plane : BspPlane;
    public var child0 : BspNode;
    public var child1 : BspNode;
    public var faces : Vector<BspFace>;
    public var cluster : Int;
    public var bmins : Vec3f;
    public var bmaxs : Vec3f;
    public var color : UInt;
        
    public function new()
    {
        bmins = new Vec3f( Math.POSITIVE_INFINITY, Math.POSITIVE_INFINITY, Math.POSITIVE_INFINITY );
        bmaxs = new Vec3f( Math.NEGATIVE_INFINITY, Math.NEGATIVE_INFINITY, Math.NEGATIVE_INFINITY );
    }
    
	// Renders the node ( and its children recursively ) in correct order for a given renderSession.
    public function render( rsession : BspRenderSession ) : Void {
        var proj = rsession.proj;
        if ( !proj.cullAABox( bmins, bmaxs ) ) return;
        
        if ( plane != null ) { // Node is not a leaf
            if ( !proj.cullPlane( plane.normal, plane.dist ) ) {
                child0.render(rsession);
                child1.render(rsession);
            }else {
                child1.render(rsession);
                child0.render(rsession);
            }
        }else { // Node is a leaf
            var visMatIdx = cluster * rsession.visData.rowSize + rsession.cameraCluster;
            if ( visMatIdx >= 0 && !rsession.visData.visMat[visMatIdx] ) return;
            
            for ( face in faces ) {
                if ( proj.cullPlane( face.normal, face.dist ) ) {
                    face.color = color;
                    
                    face.render( rsession );
                }
            }
        }

    }
    
	// Obtains the leaf node that contains p.
    public function leafForPoint( p : Vec3f ) : BspNode {
        if ( plane != null ) { // Node is not a leaf
            if ( plane.normal.dot(p) - plane.dist > 0 ) {
                return child0.leafForPoint(p);
            }else {
                return child1.leafForPoint(p);
            }
        }else { // Node is a leaf
            return this;
        }
    }
    
	// Trims all geometry from itself and its children using the given plane.
    public function clip( normal : Vec3f, dist : Float ) : Void {
        
        if ( null != plane ) {
            child0.clip(normal, dist);
            child1.clip(normal, dist);
        }else {
            var newFaces = new Vector<BspFace>();
            for ( f in faces ) {
                f.clip(normal, dist);
                
                if ( f.numTris > 0 ) newFaces.push(f);
            }
            faces = newFaces;
        }
    }
    
	// Cleaning algorithm, ensures that the geometry of each leaf is contained in its partition ( By clipping ).
    public function clean( clipPlanes : Vector<BspPlane> = null ) : Void {
        if ( clipPlanes == null ) clipPlanes = new Vector<BspPlane>();
        
        if ( plane != null ) {
            clipPlanes.push( plane.clone() );
            child0.clean(clipPlanes);
            
            bmins.cMin(bmins, child0.bmins);
            bmaxs.cMax(bmaxs, child0.bmaxs);
            
            clipPlanes[clipPlanes.length-1].invert();
            child1.clean(clipPlanes);
            
            bmins.cMin(bmins, child1.bmins);
            bmaxs.cMax(bmaxs, child1.bmaxs);
            
            clipPlanes.pop();
        }else {
            var newFaces = new Vector<BspFace>();
            for ( f in faces ) {
                for ( p in clipPlanes ) {
                    f.clip(p.normal, p.dist);
                }
                if ( f.numTris > 0 ) {
                    newFaces.push(f);
                    f.dist = f.normal.dot(f.verts[0].pos);
                    
                    for ( v in f.verts ) {
                       bmins.cMin( bmins, v.pos );
                       bmaxs.cMax( bmaxs, v.pos );
                    }
                }
                
                
            }
            faces = newFaces;
        }
    }

}